#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <err.h>
#include <sysexits.h>

#include <zahl.h>

#include "dc.h"
#include "util.h"

void
zgetu(uint64_t *o, z_t v, size_t n)
{
	size_t b;

	assert(o != NULL && n <= 64);
	for (b = n, *o = 0; b > 0; )
		if (zbtest(v, --b))
			*o |= UINT64_C(1) << b;
}

void *
memdup(const void *p, size_t s)
{
	void *r;

	if (p == NULL)
		return (NULL);
	if ((r = malloc(s)) == NULL)
		return (NULL);
	(void)memcpy(r, p, s);
	return (r);
}

void *
dallot(struct data *data, size_t ds)
{
	void *p;

	assert(data != NULL);
	if ((p = allot(&data->data, &data->mmemb, data->nmemb,
	    data->size, ds)) == NULL)
		return (NULL);
	data->nmemb++;
	return (p);
}

void *
allot(void **ptr, size_t *size, size_t nmemb, size_t msize, size_t ds)
{
	void *p;

	assert(ptr != NULL && size != NULL);
	if (*ptr == NULL)
		*size = 0;
	if (msize == 0)
		errc(EX_SOFTWARE, EDOM, "allot");
	if (*size >= *size + ds * msize)
		errc(EX_SOFTWARE, EOVERFLOW, "allot");
	if (*size / msize <= nmemb) {
		if (ds == 0)
			return (NULL);
		if ((p = (*ptr == NULL ? malloc(ds * msize) :
		    realloc(*ptr, *size + ds * msize))) == NULL)
			err(EX_OSERR, "allot");
		*ptr = p;
		*size += ds * msize;
	}
	return (((char *)*ptr) + nmemb * msize);
}
